# coding: utf-8
from typing import List

from PySide6.QtCore import Qt, Signal, QSize
from PySide6.QtGui import QWheelEvent
from PySide6.QtWidgets import QHBoxLayout, QWidget, QVBoxLayout, QScroller, QScrollerProperties
from qfluentwidgets import FluentIcon, SingleDirectionScrollArea
from qfluentwidgets.components.widgets.flip_view import ScrollButton


class BannerView(SingleDirectionScrollArea):
    currentIndexChanged = Signal(int)

    def __init__(self, parent=None, orient=Qt.Orientation.Horizontal):
        super().__init__(parent, orient)
        self.__currentIndex = 0
        self.isHover = False
        self._items = []  # type: List[QWidget]
        self.view = QWidget(self)
        self.preButton = ScrollButton(self)
        self.nextButton = ScrollButton(self)

        self.__initWidgets()

    def __initWidgets(self):
        self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.setWidget(self.view)
        self.setWidgetResizable(True)
        self.view.setAutoFillBackground(False)
        self.enableTransparentBackground()

        scroller = QScroller.scroller(self)
        scroller.grabGesture(self, QScroller.ScrollerGestureType.LeftMouseButtonGesture)
        properties = QScrollerProperties()
        properties.setScrollMetric(QScrollerProperties.ScrollMetric.DecelerationFactor, 0.5)
        scroller.setScrollerProperties(properties)

        if self.orientation() == Qt.Orientation.Horizontal:
            self.setLayout(QHBoxLayout(self))
            self.view.setLayout(QHBoxLayout(self.view))
            self.view.layout().setAlignment(Qt.AlignmentFlag.AlignLeft)
            self.preButton.setIcon(FluentIcon.CARE_LEFT_SOLID)
            self.nextButton.setIcon(FluentIcon.CARE_RIGHT_SOLID)
            self.preButton.setFixedSize(16, 38)
            self.nextButton.setFixedSize(16, 38)
        else:
            self.setLayout(QVBoxLayout(self))
            self.view.setLayout(QVBoxLayout(self.view))
            self.view.layout().setAlignment(Qt.AlignmentFlag.AlignTop)
            self.preButton.setIcon(FluentIcon.CARE_UP_SOLID)
            self.nextButton.setIcon(FluentIcon.CARE_DOWN_SOLID)
            self.preButton.setFixedSize(38, 16)
            self.nextButton.setFixedSize(38, 16)

        self.layout().setContentsMargins(0, 0, 0, 0)
        self.view.layout().setAlignment(Qt.AlignmentFlag.AlignLeft)
        self.view.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addWidget(self.preButton, 0, Qt.AlignmentFlag.AlignLeft)
        self.layout().addStretch(1)
        self.layout().addWidget(self.nextButton, 0, Qt.AlignmentFlag.AlignRight)

        self.preButton.clicked.connect(self.scrollPrevious)
        self.nextButton.clicked.connect(self.scrollNext)

        self.preButton.setVisible(False)
        self.nextButton.setVisible(False)

    def isHorizontal(self) -> bool:
        return self.orient == Qt.Orientation.Horizontal

    def scrollTo(self, value: int):
        if self.orientation() == Qt.Orientation.Horizontal:
            self.hScrollBar.scrollTo(value, True)
        else:
            print("not implemented")
            self.vScrollBar.scrollTo(value, True)

    def scrollToIndex(self, index: int):
        item = self._items[index]
        self.scrollTo(item.x())

    def setCurrentIndex(self, index: int):
        if index < 0 or index >= len(self._items):
            return
        self.__currentIndex = index

        self.scrollToIndex(index)
        # update the visibility of scroll button
        if index == 0:
            self.preButton.fadeOut()
        elif self.preButton.isTransparent() and self.isHover:
            self.preButton.fadeIn()

        if index == self.count() - 1:
            self.nextButton.fadeOut()
        elif self.nextButton.isTransparent() and self.isHover:
            self.nextButton.fadeIn()

        # fire signal
        self.currentIndexChanged.emit(index)

    def currentIndex(self) -> int:
        return self.__currentIndex

    def count(self) -> int:
        return len(self._items)

    def scrollPrevious(self):
        """ scroll to previous item """
        self.setCurrentIndex(self.currentIndex() - 1)

    def scrollNext(self):
        """ scroll to next item """
        self.setCurrentIndex(self.currentIndex() + 1)

    def addWidget(self, widget: QWidget):
        self._items.append(widget)
        self.view.layout().addWidget(widget)

    def setSpacing(self, spacing: int):
        self.view.layout().setSpacing(spacing)

    def orientation(self) -> Qt.Orientation:
        return self.orient

    def removeWidget(self, widget: QWidget):
        self._items.remove(widget)
        self.view.layout().removeWidget(widget)
        widget.deleteLater()

    def clear(self):
        for item in self._items:
            self.view.layout().removeWidget(item)
        self._items.clear()

    def enterEvent(self, e):
        super().enterEvent(e)
        self.isHover = True

        # if self.currentIndex() > 0:
        #     self.preButton.fadeIn()
        #
        # if self.currentIndex() < self.count() - 1:
        #     self.nextButton.fadeIn()

    def leaveEvent(self, e):
        super().leaveEvent(e)
        self.isHover = False
        # self.preButton.fadeOut()
        # self.nextButton.fadeOut()

    def wheelEvent(self, e: QWheelEvent):
        e.ignore()

    def sizeHint(self) -> QSize:
        if self.count() == 0:
            return super().sizeHint()
        else:
            size = self._items[0].sizeHint()
            viewportMargins = self.viewportMargins()
            return QSize(self.width(), size.height() + viewportMargins.top() + viewportMargins.bottom())


class HorizontalBannerView(BannerView):
    def __init__(self, parent=None):
        super().__init__(parent, Qt.Orientation.Horizontal)


class VerticalBannerView(BannerView):
    def __init__(self, parent=None):
        super().__init__(parent, Qt.Orientation.Vertical)
